package com.weme.common.manager

import com.google.protobuf.ByteString
import com.osom.proto.message.NetworkOuterClass
import com.weme.common.buff.IoBuffer
import com.weme.common.socket.base.DecoderAdapter
import com.weme.common.socket.base.DecoderCoderOutput
import org.java_websocket.client.WebSocketClient
import java.nio.ByteBuffer
import java.nio.ByteOrder

/**
 * 消息解码器
 *
 * @author 
 */
class Decoder : DecoderAdapter {
    private val ctx = Context()


    override fun decode(client: WebSocketClient?, inBuff: ByteBuffer?, output: DecoderCoderOutput) {
        inBuff?.let {
            decodeInner(it, output)
        }
    }

    private fun decodeInner(inBuff: ByteBuffer, output: DecoderCoderOutput) {
        ctx.append(inBuff)
        val ioBuff = ctx.buff
        ioBuff.flip()
        while (ioBuff.remaining() >= 4) {
            //标记一下当前position的位置
            ioBuff.mark()

            //取出头部信息，即包体的长度
            val header = ByteArray(4)
            ioBuff.get(header)
            val headerBuff = IoBuffer.allocate(header.size).order(ByteOrder.LITTLE_ENDIAN)
            headerBuff.put(header)
            headerBuff.flip()
            val length = headerBuff.unsignedInt.toInt()

            //如果长度小于0
            if (length < 0) {
                ioBuff.clear()
                break
            } else if (length <= ioBuff.remaining()) {
                //刚好或则粘包了

                //存储一下old limit
                val limit = ioBuff.limit()
                //设置一下当前包应该的limit
                ioBuff.limit(ioBuff.position() + length)
                val content = ByteArray(length)
                ioBuff.get(content)
                //读取完了之后，设置回原来的limit
                ioBuff.limit(limit)
                //转换成protobuf数据
                val network = NetworkOuterClass.Network.parseFrom(content)
                //解密
                val payload = network.payload.toByteArray()
                val decryptNetWork = NetworkOuterClass.Network.newBuilder(network)
                    .setPayload(ByteString.copyFrom(payload))
                    .build()
                output.write(decryptNetWork)

                //读取完一条数据了，再次进行while，如果还大于4可以继续读下一条数据
            } else {
                //分包了,数据不够了，等一下次数据过来合并
                ioBuff.reset()
                break
            }
        }

        if (ioBuff.hasRemaining()) {
            //如果还有没有读取的数据，要保存下来和下次服务器过来的数据合并读取
            val temp = IoBuffer.allocate(100).setAutoExpand(true)
            //将原来剩余的数据放到temp buff中
            temp.put(ioBuff)
            temp.flip()
            ioBuff.clear()
            ioBuff.put(temp)
        } else {
            ioBuff.clear()
        }
    }
}

class Context {

    var buff: IoBuffer = IoBuffer.allocate(100).setAutoExpand(true)

    fun append(buff: IoBuffer) {
        this.buff.put(buff)
    }

    fun append(buff: ByteBuffer) {
        this.buff.put(buff)
    }
}